package com.mygdx.game;

import java.util.ArrayList;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.math.Vector2;
import com.mygdx.game.model.Rock;
import com.mygdx.game.model.Ship;

public class MyGdxGame extends Game {
	
	static final int SPEED = 500;
	static final int ACCELERATION = 20;
	
//	ShapeRenderer shapeRenderer;
	SpriteBatch batch;
	OrthographicCamera camera;
	
	Texture background;
	
	Ship ship;
	GridPoint2 touchPoint;
	ArrayList<Rock> rocks;
	
//	BitmapFont font;
//	String score;
	
	float planeStateTime = 0;
	float lastDelta;
	int decelerateValue;
	boolean atGoal = false;
	
//	ArrayBlockingQueue<Float> distances;
	
	@Override
	public void create () {
		
//		shapeRenderer = new ShapeRenderer();
		batch = new SpriteBatch();
		camera = new OrthographicCamera();
		camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		
		ship = new Ship();
		rocks = new ArrayList<Rock>();
		
//		font = new BitmapFont(Gdx.files.internal("arial.fnt"));
		
		resetWorld();
	}
	
	private void resetWorld() {
		camera.position.x = Gdx.graphics.getWidth()/2;
		camera.position.y = Gdx.graphics.getHeight()/2;
		
//		distances = new ArrayBlockingQueue<Float>(5);
		
		ship.reset();
		
		makeRock();
	}
	
	private void makeRock() {
		Rock rock = new Rock();
		rock.setPosition(new Vector2(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()));
		rock.setVelocity(new Vector2(0, -100));
		rocks.add(rock);
	}

	@Override
	public void render () {
		Gdx.gl.glClearColor(1, 1, 1, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		
		updateWorld();
		drawWorld();	
	}
	
	float totalDelta = 0;
	float xTargetSpeed = 0;
	float yTargetSpeed = 0;
	float xAcceleration = 0;
	float yAcceleration = 0;
	
	boolean decelerate = false;
	
	private void updateWorld()
	{
		float deltaTime = Gdx.graphics.getDeltaTime();
		planeStateTime += deltaTime;
		
		if(Gdx.input.justTouched()) 
		{
			atGoal = false;
			
			touchPoint = new GridPoint2(Gdx.input.getX(), Gdx.input.getY());
			lastDelta = 0;
			decelerate = false;
			
//			score = "Plane("+planePosition.x+","+planePosition.y+"), Touch("+touchPoint.x+","+touchPoint.y+")";
//			Gdx.app.log("Plane", score);
		}
		
		if (touchPoint != null)
		{
			float deltaX = touchPoint.x - ship.posX();
			float deltaY = (int)(Gdx.graphics.getHeight()-touchPoint.y) - ship.posY();
			totalDelta = Math.abs(deltaX)+Math.abs(deltaY);
			
//			Gdx.app.log("Plane", "Plane("+planePosition.x+","+planePosition.y+"), Touch("+touchPoint.x+","+touchPoint.y+")"+"Height("+Gdx.graphics.getHeight()+")");
//			Gdx.app.log("Plane", "DeltaX:"+deltaX+" - DeltaY:"+deltaY + " - VelX:"+planeVelocity.x + " - VelY:"+planeVelocity.y);
//			score = "Plane("+planePosition.x+","+planePosition.y+"), Touch("+touchPoint.x+","+touchPoint.y+")"+"Deltas("+deltaX +":" + deltaY +")";
//			Gdx.app.log("Plane", score);
			
			float speedX = deltaX/totalDelta;
			float speedY = deltaY/totalDelta;
			
			xTargetSpeed = SPEED*speedX;
			yTargetSpeed = SPEED*speedY;
			xAcceleration = ACCELERATION*speedX;
			yAcceleration = ACCELERATION*speedY;
//			Gdx.app.log("Plane", "SpeedX:"+speedX + " - SpeedY:"+ speedY);
			
			if (!decelerate) {
				
				if (ship.velX() != xTargetSpeed) {
					float currentVelocityX = ship.velX();
					
					if (xTargetSpeed < 0 && ship.velX() > 0) {
						ship.subVx(ACCELERATION);
					} else if ( xTargetSpeed > 0 && ship.velX() < 0) {
						ship.addVx(ACCELERATION);
					} else {
						if (ship.velX() > 0) {
							if (ship.velX() > xTargetSpeed) {
								if (ship.velX() - ACCELERATION > xTargetSpeed)
									ship.subVx(ACCELERATION);
								else
									ship.setVx(xTargetSpeed);
							} else {
								ship.addVx(xAcceleration);
							}
						} else if (ship.velX() < 0) {
							if (ship.velX() < xTargetSpeed) {
								if (ship.velX() + ACCELERATION < xTargetSpeed)
									ship.addVx(ACCELERATION);
								else
									ship.setVx(xTargetSpeed);
							} else {
								ship.addVx(xAcceleration);
							}
						} else {
							ship.addVx(xAcceleration);
						}
					}
					
					if (currentVelocityX < xTargetSpeed && xTargetSpeed < ship.velX()) {
						ship.setVx(xTargetSpeed);
					} else if (currentVelocityX > xTargetSpeed && xTargetSpeed > ship.velX()) {
						ship.setVx(xTargetSpeed);
					}
				}
				
				if (ship.velY() != yTargetSpeed) {
					float currentVelocityY = ship.velY();
					
					if (yTargetSpeed < 0 && ship.velY() > 0) {
						ship.subVy(ACCELERATION);
					} else if ( yTargetSpeed > 0 && ship.velY() < 0) {
						ship.addVy(ACCELERATION);
					} else {
						if (ship.velY() > 0) {
							if (ship.velY() > yTargetSpeed) {
								if (ship.velY() - ACCELERATION > yTargetSpeed)
									ship.subVy(ACCELERATION);
								else
									ship.setVy(yTargetSpeed);
							}
							else {
								ship.addVy(yAcceleration);
							}
						} else if (ship.velY() < 0) {
							if (ship.velY() < yTargetSpeed) {
								if (ship.velY() + ACCELERATION < yTargetSpeed)
									ship.addVy(ACCELERATION);
								else
									ship.setVy(yTargetSpeed);
							}
							else {
								ship.addVy(yAcceleration);
							}
						} else {
							ship.addVy(yAcceleration);
						}
					}
					
					if (currentVelocityY < yTargetSpeed && yTargetSpeed < ship.velY()) {
						ship.setVy(yTargetSpeed);
					} else if (currentVelocityY > yTargetSpeed && yTargetSpeed > ship.velY()) {
						ship.setVy(yTargetSpeed);
					}
				}
				
//				if (distances.size() == 5) {
//					distances.poll();
//				}
				float distancePerTick = Math.abs(totalDelta - lastDelta);
//				distances.add(distancePerTick);
//				float averageDistance = 0;
//				float distanceSum = 0;
//				for (Float f : distances) {
//					distanceSum += f;
//				}
//				averageDistance = distanceSum / distances.size();
				
				if (lastDelta > 0) {
//					Gdx.app.log("Plane", "dpt:"+distancePerTick + " - tmp:"+temp+" - del:"+totalDelta);
					int currentSpeed = (int) ship.currentSpeed();
					decelerateValue = (currentSpeed + ACCELERATION) * (currentSpeed / ACCELERATION) / 2;
					if (( distancePerTick / currentSpeed ) * decelerateValue > totalDelta) {
						decelerate = true;
					}
				}
				
			} else {
//				Gdx.app.log("Plane", "slowing down");
				if (ship.currentSpeed() > 3*ACCELERATION) {
					ship.subVx(xAcceleration);
					ship.subVy(yAcceleration);
				}
			}
			
//			Gdx.app.log("Plane", "atGoal:"+atGoal + " - lst:" +lastDelta+" - ttl:"+totalDelta);
			if (atGoal && totalDelta > lastDelta && totalDelta < 20) {
				ship.stop();
				touchPoint = null;
			}
			else if (!atGoal && totalDelta < lastDelta) {
				atGoal = true;
			}
		}
		
		if (!ship.isStopped()) {
			ship.mulAddAtTime(deltaTime);
		}
		
		lastDelta = totalDelta;
		
		for (Rock rock : rocks) {
			rock.mulAddAtTime(deltaTime);
			if (rock.getY() < 0) {
				rocks.remove(rock);
				makeRock();
			}
			
		}
	}
	
	private void drawWorld()
	{
		camera.update();
		batch.setProjectionMatrix(camera.combined);
		
		batch.begin();
		
		batch.draw(ship.getDrawTexture(planeStateTime), ship.getDrawX(), ship.getDrawY());
		for (Rock rock : rocks) {
			batch.draw(rock.getImage(), rock.getX(), rock.getY());
	    }
		
		batch.end();
		
		
//		ShapeRenderer renderer = new ShapeRenderer();
//		renderer.setProjectionMatrix(camera.combined);
//		renderer.begin(ShapeType.Filled);
//		renderer.setColor(1,0,0,1);
//		for (Rock rock : rocks) {
//			renderer.circle(rock.getX(), rock.getY(), rock.getR());
//		}
//		renderer.identity();
//		renderer.end();
	}
	
	@Override
	public void resize(int width, int height) {
	}
	
	@Override
	public void pause() {
	}
	
	@Override
	public void resume() {
	}
	
	@Override
	public void dispose() {
	}
}
